using System;
using Godot;
using PaintAWorld.PlayerInputs;
using ZFramework;

namespace PaintAWorld.Gd
{
	public partial class PlayerNode : Node3D
	{
		private const float EyePitchLimit = 0.48f * Mathf.Pi;

		public Level level;

		[ExportGroup("Links")]
		[Export]
		public Camera3D eye;

		[ExportGroup("Datas")]
		[Export]
		public float speed;

		private Vector3 _velocity = new();
		private Rgba32[] _shortcut = [Rgba32.Red, Rgba32.Orange, Rgba32.Yellow, Rgba32.Green, Rgba32.Cyan, Rgba32.Blue, Rgba32.Magenta, Rgba32.White, Rgba32.Black];
		private byte _shortcutIndex = 0;

		public Vector3 EyeRotation => eye.GlobalRotation;
		public Rgba32 CurrentColor => _shortcut[_shortcutIndex];
		public byte CurrentIndex => _shortcutIndex;

		public override void _Process(double delta)
		{
			Position += _velocity * (float)delta;
		}

		public void Look(Vector2 deltaRotation)
		{
			var rotationNew = eye.GlobalRotation + new Vector3(-deltaRotation.Y, -deltaRotation.X, 0);
			rotationNew.X = Mathf.Clamp(rotationNew.X, -EyePitchLimit, EyePitchLimit);
			eye.GlobalRotation = rotationNew;
		}

		public void Move(Vector2 direction, float verticalAxis)
		{
			_velocity = speed * (CalLocalDir(direction) + new Vector3(0, verticalAxis, 0));
		}

		public IPlayerInputContent Primary()
		{
			return QueryDigPos() is Vector3I pos ? new RemoveVoxel(pos) : null;
		}

		public IPlayerInputContent Secondary()
		{
			return QueryPlacePos() is Vector3I pos ? new SetVoxel(pos, CurrentColor) : null;
		}

		public Vector3I? QueryPlacePos()
		{
			if (level.World.GetMap().Intersects(GetInteractRay(), 32) is VoxelHitResult hit && hit.normal is Vec3 normal)
			{
				var target = hit.voxelPos + normal.FloorToInt();
				return target;
			}
			return null;
		}

		public Vector3I? QueryDigPos()
		{
			if (level.World.GetMap().Intersects(GetInteractRay(), 32) is VoxelHitResult hit)
			{
				return hit.voxelPos;
			}
			return null;
		}

		public void MoveShortcut(byte index)
		{
			_shortcutIndex = index;
		}

		public void MoveNextShortcut()
		{
			MoveShortcut((byte)((_shortcutIndex + 1) % _shortcut.Length));
		}

		public void MoveBackShortcut()
		{
			MoveShortcut((byte)((_shortcutIndex - 1 + _shortcut.Length) % _shortcut.Length));
		}

		private Vector3 CalLocalDir(Vector2 direction)
		{
			var dir = eye.GlobalTransform.Basis * new Vector3(direction.X, 0, direction.Y);
			dir.Y = 0;
			return dir.Normalized();
		}

		private Ray GetInteractRay()
		{
			var crosshairPos = (Vector2)GetWindow().Size * 0.5f;
			return new Ray(eye.ProjectRayOrigin(crosshairPos), eye.ProjectRayNormal(crosshairPos));
		}

		// private (Vector3I position, Vector3I normal)? QueryLookInfo()
		// {
		// 	var spaceState = GetWorld3D().DirectSpaceState;
		// 	var mousePosition = (Vector2)GetWindow().Size * 0.5f;

		// 	var origin = eye.ProjectRayOrigin(mousePosition);
		// 	var end = origin + eye.ProjectRayNormal(mousePosition) * 7;
		// 	var query = PhysicsRayQueryParameters3D.Create(origin, end);

		// 	var result = spaceState.IntersectRay(query);

		// 	if (result.Count > 0)
		// 	{
		// 		var shape = result["shape"].AsInt32();
		// 		var collider = result["collider"].As<CollisionObject3D>();
		// 		var ownerId = collider.ShapeFindOwner(shape);
		// 		var transform = collider.ShapeOwnerGetTransform(ownerId);

		// 		return ((Vector3I)transform.Origin.Floor(), (Vector3I)result["normal"].As<Vector3>().Floor());
		// 	}
		// 	return null;
		// }
	}
}